/*
**  Copyright (c) 2014 Michael Liu(michael.liu.point@gmail.com).
**
**  Project: Gateway Unified Management Platform
**  File:      svcmgr.c
**  Author:  Michael
**  Date:    03/20/2014
**
**  Purpose:
**    service manager related implement.
*/

/* Include files. */

#include "common.h"
#include "svcmgr.h"

/* Macro constant definitions. */

/* Type definitions. */

/* Local function declarations. */

static e_ret svcmgr_check_service(tos_dep_task task, int status);
static tsm_svc *svcmgr_find_service_by_name(const char *name);
static tsm_svc *svcmgr_find_service_by_task(tos_dep_task task);

/* Macro API definitions. */

/* Global variable declarations. */

struct list_head sm_svc_list;
tos_dep_mutex sm_svc_list_mutex;

e_ret svcmgr_init()
{
	sysmgr_trace_enter();

	INIT_LIST_HEAD(&sm_svc_list);
	os_dep_mutex_init(&sm_svc_list_mutex);

	sysmgr_trace_exit();
	return (eRET_SUCCESS);
}

e_ret svcmgr_check()
{

	int rc;
	int status;
	tos_dep_task task;

	sysmgr_trace_enter();

	do {
		task = -1;
		rc = os_dep_wait(&task, &status, WNOHANG);

		if (task > 0) {
			svcmgr_check_service(task, status);
		} else {
			break;
		}
	} while (1);

	sysmgr_trace_exit();
	return (eRET_SUCCESS);
}

e_ret svcmgr_check_service(tos_dep_task task, int status)
{

	tsm_svc *svc;

	sysmgr_trace_enter();

#if 0
	sysmgr_dbg("system task[%d] exit, status[0x%08X], WIFEXITED:0x%08X, "
		   "WEXITSTATUS:0x%08X, WIFSIGNALED:0x%08X, WTERMSIG:0x%08X.\n",
		   task, status, WIFEXITED(status), WEXITSTATUS(status), WIFSIGNALED(status), WTERMSIG(status));
#endif

	sysmgr_dbg("system task[%d] exit, check system services.\n", task);
	svc = svcmgr_find_service_by_task(task);
	if (svc != NULL) {
		sysmgr_dbg("system svc[%s] exit. restart it.\n", svc->name);
		if ((svc->enable) && (svc->start != NULL)) {
			svc->start(svc);
		}
		sysmgr_trace_exit();
		return (eRET_SUCCESS);
	}

	sysmgr_trace_exit();
	return (eRET_NOT_EXIST);

}

tsm_svc *svcmgr_find_service_by_name(const char *name)
{

	struct list_head *each;
	tsm_svc *svc;

	sysmgr_trace_enter();

	list_for_each(each, &sm_svc_list) {
		svc = list_entry(each, tsm_svc, list);
		if (strcmp(svc->name, name) == 0) {
			sysmgr_trace_exit();
			return (svc);
		}
	}

	sysmgr_dbg("service name[%s] is NOT a system svc.\n", name);

	sysmgr_trace_exit();
	return (NULL);

}

tsm_svc *svcmgr_find_service_by_task(tos_dep_task task)
{
	struct list_head *each;
	tsm_svc *svc;

	sysmgr_trace_enter();

	list_for_each(each, &sm_svc_list) {
		svc = list_entry(each, tsm_svc, list);
		if (svc->task == task) {
			sysmgr_trace_exit();
			return (svc);
		}
	}

	sysmgr_dbg("system task[%d] is NOT a system svc.\n", task);

	sysmgr_trace_exit();
	return (NULL);

}

e_ret svcmgr_add_svc(tsm_svc * svc)
{

	e_ret ret;

	sysmgr_trace_enter();

	os_dep_mutex_lock(&sm_svc_list_mutex);

	if (svcmgr_find_service_by_name(svc->name) != NULL) {
		sysmgr_dbg("Sysmte Service[%s] already exist.\n", svc->name);
		ret = eRET_ALREADY_EXIST;
		goto out;
	}

	list_add(&svc->list, &sm_svc_list);
	ret = eRET_SUCCESS;

out:
	os_dep_mutex_unlock(&sm_svc_list_mutex);
	sysmgr_trace_exit();
	return (ret);

}

e_ret svcmgr_del_svc(tsm_svc * svc)
{

	e_ret ret;

	sysmgr_trace_enter();

	os_dep_mutex_lock(&sm_svc_list_mutex);

	if (svcmgr_find_service_by_name(svc->name) == NULL) {
		sysmgr_err("Sysmte Service[%s] not exist.\n", svc->name);
		ret = eRET_NOT_EXIST;
		goto out;
	}

	list_del(&svc->list);
	ret = eRET_SUCCESS;

out:
	os_dep_mutex_unlock(&sm_svc_list_mutex);
	sysmgr_trace_exit();
	return (ret);

}

e_ret svcmgr_find_svc(const char *name, tsm_svc ** svc)
{

	e_ret ret;

	sysmgr_trace_enter();
	os_dep_mutex_lock(&sm_svc_list_mutex);

	if ((*svc = svcmgr_find_service_by_name(name)) == NULL) {
		sysmgr_dbg("Sysmte Service[%s] not exist.\n", name);
		ret = eRET_NOT_EXIST;
		goto out;
	}

	ret = eRET_SUCCESS;

out:
	os_dep_mutex_unlock(&sm_svc_list_mutex);
	sysmgr_trace_exit();
	return (ret);

}
